import sys
import subprocess
from typing import Optional, Dict, Any
from .base import BaseNotifier
import win32gui
import win32con
import win32api
import platform
from win10toast import ToastNotifier
import os
import logging
import winreg

logger = logging.getLogger(__name__)

class WindowsNotifier(BaseNotifier):
    def __init__(self):
        super().__init__()
        if sys.platform != 'win32':
            raise RuntimeError("WindowsNotifier can only be used on Windows")
            
        # 获取配置
        from ..config import Config
        self.config = Config()
            
        self.wc = win32gui.WNDCLASS()
        self.hinst = self.wc.hInstance = win32gui.GetModuleHandle(None)
        self.wc.lpszClassName = "WSNotifierClass"
        self.wc.lpfnWndProc = self.wnd_proc
        self.classAtom = win32gui.RegisterClass(self.wc)
        
        # 初始化通知器
        self.win10_notifier = None
        self.windows_version = int(platform.version().split('.')[0])
        
        # Windows 10 (10.0) 及以上版本使用 ToastNotifier
        if self.windows_version >= 10:
            try:
                # 注册应用程序
                self._register_app()
                self.win10_notifier = ToastNotifier()
                # 设置应用程序 ID
                self.win10_notifier.app_id = self.config.APP_ID
            except Exception as e:
                logger.warning(f"Failed to initialize Win10 ToastNotifier: {e}")
    
    def _register_app(self):
        """注册 Windows 应用程序"""
        try:
            # 创建注册表项
            key_path = r"Software\Classes\AppUserModelId"
            with winreg.CreateKey(winreg.HKEY_CURRENT_USER, f"{key_path}\\{self.config.APP_ID}") as key:
                winreg.SetValueEx(key, "DisplayName", 0, winreg.REG_SZ, self.config.APP_NAME)
                winreg.SetValueEx(key, "IconUri", 0, winreg.REG_SZ, self.config.TRAY_ICON_PATH)
                winreg.SetValueEx(key, "IconBackgroundColor", 0, winreg.REG_SZ, "(0, 120, 215)")
            
        except Exception as e:
            logger.error(f"Failed to register application: {e}")

    def _send_notification(self, title: str, message: str, timeout: int = 10) -> None:
        """
        分层通知实现：
        1. Windows 10/11: 优先使用 ToastNotifier
        2. 如果 ToastNotifier 失败，回退到 PowerShell 通知
        3. 如果 PowerShell 通知失败，使用 win32gui 托盘通知
        """
        # 尝试使用 Win10 Toast 通知
        if self.win10_notifier:
            try:
                self.win10_notifier.show_toast(
                    title,
                    message,
                    duration=timeout,
                    threaded=True  # 使用线程避免阻塞
                )
                return
            except Exception as e:
                logger.debug(f"Win10 toast notification failed: {e}")

        # 尝试使用 PowerShell 通知
        try:
            self._send_powershell_notification(title, message, timeout)
            return
        except Exception as e:
            logger.debug(f"PowerShell notification failed: {e}")

        # 最后尝试使用 win32gui 托盘通知
        try:
            self._send_tray_notification(title, message, timeout)
        except Exception as e:
            self._handle_error(f"All notification methods failed: {str(e)}")

    def _send_powershell_notification(self, title: str, message: str, timeout: int) -> None:
        """PowerShell 通知实现"""
        title = title.replace("'", "''")
        message = message.replace("'", "''")
        app_name = self.config.APP_NAME.replace("'", "''")
        
        script = f'''
        [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] > $null
        [Windows.UI.Notifications.ToastNotification, Windows.UI.Notifications, ContentType = WindowsRuntime] > $null
        [Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] > $null

        $template = @"
        <toast>
            <visual>
                <binding template="ToastText02">
                    <text id="1">{title}</text>
                    <text id="2">{message}</text>
                </binding>
            </visual>
        </toast>
"@

        $xml = New-Object Windows.Data.Xml.Dom.XmlDocument
        $xml.LoadXml($template)
        $toast = New-Object Windows.UI.Notifications.ToastNotification $xml
        [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier("{app_name}").Show($toast)
        '''
        
        result = subprocess.run(
            ['powershell', '-NoProfile', '-NonInteractive', '-Command', script],
            capture_output=True,
            text=True,
            check=True
        )
        
        if result.stderr:
            raise RuntimeError(f"PowerShell error: {result.stderr}")

    def _send_tray_notification(self, title: str, message: str, timeout: int) -> None:
        """使用 win32gui 发送托盘通知"""
        try:
            from win32gui import Shell_NotifyIcon, NIM_ADD, NIM_MODIFY, NIM_DELETE, NIIF_INFO
            from win32gui import NIF_ICON, NIF_INFO, NIF_TIP, NIF_MESSAGE
            
            flags = NIF_ICON | NIF_INFO | NIF_TIP
            nid = (
                self.hinst,  # 句柄
                0,          # ID
                flags,      # 标志
                win32con.WM_USER + 20,  # 回调消息
                win32gui.LoadIcon(0, win32con.IDI_APPLICATION),  # 图标
                self.config.APP_NAME,  # 提示文本
                title,      # 标题
                timeout * 1000,  # 超时
                message,    # 消息
                NIIF_INFO  # 图标类型
            )
            Shell_NotifyIcon(NIM_ADD, nid)
            
            # 设置定时器移除通知图标
            win32api.SetTimer(self.hinst, 1, timeout * 1000, None)
            
        except Exception as e:
            raise RuntimeError(f"Tray notification failed: {str(e)}")

    def wnd_proc(self, hwnd, msg, wparam, lparam):
        """窗口消息处理函数"""
        try:
            if msg == win32con.WM_DESTROY:
                win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, (self.hinst, 0))
                win32gui.PostQuitMessage(0)
                return 0
            elif msg == win32con.WM_TIMER:
                # 清理托盘图标
                win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, (self.hinst, 0))
                win32gui.KillTimer(self.hinst, wparam)
                return 0
            elif msg == win32con.WM_USER + 20:
                # 处理托盘图标的消息
                return 0
            
            # 确保所有消息都返回一个整数值
            result = win32gui.DefWindowProc(hwnd, msg, wparam, lparam)
            return result if result is not None else 0
            
        except Exception as e:
            logger.error(f"Error in window procedure: {e}")
            return 0  # 确保即使发生错误也返回一个有效值

    def __del__(self):
        try:
            win32gui.UnregisterClass(self.wc.lpszClassName, self.hinst)
        except:
            pass 